package com.hz.copyingsystem.controller;

import com.alibaba.fastjson.JSON;
import com.hz.common.utils.Download;
import com.hz.common.utils.R;
import com.hz.common.utils.ResponseData;
import com.hz.copyingsystem.entity.CopyingCharacterLatticeVo;
import com.hz.copyingsystem.entity.FixedInformationDicEntity;
import com.hz.copyingsystem.feign.OssFeign;
import com.hz.copyingsystem.service.FixedInformationDicService;
import com.hz.copyingsystem.vo.*;
import com.hz.utils.FixedInformationName;
import com.hz.utils.JsonUtils;
import com.hz.utils.MD5;
import io.swagger.annotations.*;
import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.geometry.Positions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpSession;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


/**
 * @author cyl_txw
 * @email cyl_txw@gmail.com
 * @date 2023-05-09 15:02:11
 */
@RestController
@RequestMapping("layOut")
@Api(tags = "排版")
public class LayoutController {

    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    private OssFeign ossFeign;

    @Autowired
    private FixedInformationDicService fixedInformationDicService;

    /**
     * 公共背景音乐获取
     */
    @ApiOperation("公共背景音乐获取")
    @GetMapping("/backgroundMusic/get")
    public ResponseData<CopyingBackgroundMusicVo> backgroundMusicGet(){
        List<FixedInformationDicEntity> musicList = fixedInformationDicService.queryByName(FixedInformationName.CO_BACKGROUND_MUSIC);
        if (musicList.size() == 0)
            return ResponseData.success("还未上传背景音乐！");
        FixedInformationDicEntity fixedInformationDic = musicList.get(0);
        CopyingBackgroundMusicVo music = new CopyingBackgroundMusicVo(
                fixedInformationDic.getId(),
                fixedInformationDic.getFixedInformationContent(),
                fixedInformationDic.getUpdatetime()
        );
        return ResponseData.success(music);
    }


    /**
     * 获取字格背景图
     */
    @ApiOperation("获取字格背景图")
    @GetMapping("/layout/characterBg/get")
    public ResponseData<CopyingCharacterLatticeVo> layoutCharacterBgGet() {
        List<FixedInformationDicEntity> fixedInformationDicList = fixedInformationDicService.queryByName(FixedInformationName.CO_CHARACTER_LATTICE);
        List<CopyingCharacterLatticeVo> characterLatticeList = fixedInformationDicList.stream()
                .map(fixedInformationDic -> new CopyingCharacterLatticeVo(fixedInformationDic.getId(),
                        fixedInformationDic.getRemarks(),
                        fixedInformationDic.getFixedInformationContent(),
                        fixedInformationDic.getUpdatetime()))
                .collect(Collectors.toList());
        return ResponseData.success(characterLatticeList);
    }



    /**
     * 打印碑帖临摹、精临例字排版
     */
    @ApiOperation("打印碑帖临摹、精临例字排版")
    @PostMapping("/layout/steleCalliAndSeCoExamples/print")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "type", value = "排版类型。1碑帖临摹，2精临例字，3字帖", paramType = "query", dataType = "Integer", allowableValues = "1,2,3", required = true),
            @ApiImplicitParam(name = "Authorization",value = "token",paramType = "header",dataType = "String",required = true)
    })
    public ResponseData<String> layoutSteleCalliAndSeCoExamplesPrint(@RequestParam("type") Integer type, @RequestHeader("Authorization") String token) {
        String layoutName1;   // 排版内容在redis的key
        String layoutName2;    // 排版设置选项在redis的key
        Integer layoutWidth;   // 排版宽度
        Integer layoutLength;   // 排版长度
        Integer size;   // 字图大小
        String savePath;    // 获取保存路径
        Long chrBgOptionId; // 字格id
        String tokenRe = token.replace(":", "\\");
        switch (type){
            case 1:
                layoutName1 = "user:" + token + ":stelecalli:characterlist";
                layoutName2 = "user:" + token + ":stelecalli:setting";
                CopyingSteleCalligraphySettingVo steleCalliLayoutSetting = JsonUtils.toObject(
                        redisTemplate.opsForValue().get(layoutName2),
                        CopyingSteleCalligraphySettingVo.class);
                savePath = "/tmp/steleCalliLayout/"+tokenRe+"/";
                //savePath = "e:\\"+tokenRe+"\\";
                layoutWidth = steleCalliLayoutSetting.getLayoutWidth();
                layoutLength = steleCalliLayoutSetting.getLayoutLength();
                size = steleCalliLayoutSetting.getSize();
                chrBgOptionId = steleCalliLayoutSetting.getChrBgOptionId();
                break;
            case 2:
                layoutName1 = "user:" + token + ":secoexamples:exampleslist";
                layoutName2 = "user:" + token + ":secoexamples:setting";
                SelectedCopyingExamplesSettingVo seCoExamplesLayoutSetting = JsonUtils.toObject(
                        redisTemplate.opsForValue().get(layoutName2),
                        SelectedCopyingExamplesSettingVo.class);
                savePath = "/tmp/seCoExamplesLayout/"+tokenRe+"/";
                layoutWidth = seCoExamplesLayoutSetting.getLayoutWidth();
                layoutLength = seCoExamplesLayoutSetting.getLayoutLength();
                size = seCoExamplesLayoutSetting.getSize();
                chrBgOptionId = seCoExamplesLayoutSetting.getChrBgOptionId();
                break;
            default:
                return ResponseData.success("排版类型参数错误！", false);
        }
        List<CharacterVo> characterList = JsonUtils.toListOfObject(
                redisTemplate.opsForValue().get(layoutName1),
                CharacterVo.class,
                JsonUtils.createObjectMapper());

        // 获取字格图
        FixedInformationDicEntity chrBackground = fixedInformationDicService.getById(chrBgOptionId);
        // 获取图片urlList
        List<String> characterUrlList = characterList.stream()
                .map(CharacterVo::getSteleCalligraphyCharacter)
                .collect(Collectors.toList());

        String picStr = createLayoutPic(characterUrlList,
                chrBackground.getFixedInformationContent(),
                savePath,
                layoutWidth,
                layoutLength,
                size);
        if (picStr.equals(""))  return ResponseData.success("打印失败！");
        return ResponseData.success(picStr);
    }

    private String createLayoutPic(List<String> characterUrlList,
                                   String characterBgUrl,
                                   String savePath,
                                   int width,
                                   int length,
                                   int size){
        // 1判断数量是否正确
        if (characterUrlList.size() != (width*length))  return "";

        // 2下载字、字格图片
        String suffix = characterBgUrl.substring(characterBgUrl.lastIndexOf("."));
        long time = System.currentTimeMillis();
        String md5 = MD5.encrypt(characterBgUrl + time);
        String characterBgPath = savePath + md5 + suffix;
        Download.download(characterBgUrl, md5 + suffix, savePath);


        // 3生成合成图片的List<BufferedImage>
        List<BufferedImage> imagesList = new ArrayList<>();
        for (String characterUrl: characterUrlList) {
            if (characterUrl == null){
                // 如果字为空
                try {
                    BufferedImage mergeBufferedImage = Thumbnails.of(characterBgPath)
                        .size(size, size)
                        .imageType(BufferedImage.TYPE_INT_ARGB)
                        //将生成的缩略图写入文件
                        .asBufferedImage();
                    imagesList.add(mergeBufferedImage);
                } catch (IOException e) {
                    return "";
                }
                continue;
            }
            suffix = characterUrl.substring(characterUrl.lastIndexOf("."));
            md5 = MD5.encrypt(characterUrl);
            Download.download(characterUrl, md5 + suffix, savePath);
            // 将字图和字格图合成
            try {
                BufferedImage watermarkBufferedImage = Thumbnails.of(new File(savePath + md5 + suffix))
                        .size(size,size)
                        .outputQuality(1.0)
                        .imageType(BufferedImage.TYPE_INT_ARGB)
                        .asBufferedImage();
                BufferedImage mergeBufferedImage = Thumbnails.of(characterBgPath)
                    .size(size, size)
                    //指定图片类型是支持Alpha通道
                    .watermark(Positions.CENTER, watermarkBufferedImage, 1.0f)
                    .imageType(BufferedImage.TYPE_INT_ARGB)
                    //将生成的缩略图写入文件
                    .asBufferedImage();
                imagesList.add(mergeBufferedImage);
            } catch (IOException e) {
                return "";
            }
        }
        // 4制作模板图
        // 字间距大小
        int distance = size/10;
        // 计算画布宽度、长度
        int widthCanvas = size*width + (width+1)*distance;
        int lengthCanvas = size*length + (length+1)*distance;
        // 创建一个画布图片
        BufferedImage canvas = new BufferedImage(lengthCanvas,widthCanvas,BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics = canvas.createGraphics();
        // 设置颜色为218，223，224
        graphics.setColor(new Color(218,223,224));
        // 填充颜色
        graphics.fillRect(0, 0, lengthCanvas, widthCanvas);
        int startX = distance;
        int startY = distance;
        int index = 0;
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < length; j++) {
                graphics.drawImage(imagesList.get(index), startX, startY, size, size, null);
                startX += (size + distance);
                ++index;
            }
            startX = distance;
            startY += (size + distance);
        }
        graphics.dispose();
        String outputFilePath = savePath + "layout" + md5 + suffix;
        File outputFile = new File(outputFilePath);
        try {
            ImageIO.write(canvas, "png", outputFile);
        } catch (IOException e) {
            return "";
        }
        // 5上传模板图
        R upload = ossFeign.uploadZip(outputFilePath);
        String layoutOssSrc = (String) upload.get("url");
        // 6移除目录下的所有文件
        File directory = new File(savePath);
        if (directory.exists() && directory.isDirectory()){
            File[] files = directory.listFiles();
            for (File file : files) {
                if (file.exists())  file.delete();
            }
            directory.delete();
        }
        // 6返回模板图url
        return layoutOssSrc;
    }

    /**
     * 保存精临例字到排版
     */
    @ApiOperation("保存精临例字到排版")
    @PostMapping("/layout/seCoExamples/save")
    public ResponseData layoutSeCoExamplesSave(@RequestBody SelectedCopyingExamplesValueVo selectedCopyingExamples , @RequestHeader("Authorization") String token) {
        // 判断接收参数空否
        if (selectedCopyingExamples == null || selectedCopyingExamples.getCharacterList() == null || selectedCopyingExamples.getSetting() == null)
            return ResponseData.success("保存失败！",false);
        String layoutName1 = "user:" + token + ":secoexamples:exampleslist";
        String layoutName2 = "user:" + token + ":secoexamples:setting";
        redisTemplate.opsForValue().set(layoutName1, JSON.toJSONString(selectedCopyingExamples.getCharacterList()), 2, TimeUnit.HOURS);
        redisTemplate.opsForValue().set(layoutName2, JSON.toJSONString(selectedCopyingExamples.getSetting()), 2, TimeUnit.HOURS);
        return ResponseData.success("保存成功！");
    }

    /**
     * 获取精临例字排版
     */
    @ApiOperation("获取精临例字排版")
    @PostMapping("/layout/seCoExamples/get")
    @ApiImplicitParam(name = "Authorization",value = "token",paramType = "header",dataType = "String",required = true)
    public ResponseData<SelectedCopyingExamplesValueVo> layoutSeCoExamplesGet(@RequestHeader("Authorization") String token) {
        String layoutName1 = "user:" + token + ":secoexamples:exampleslist";
        String layoutName2 = "user:" + token + ":secoexamples:setting";

        String layoutNameStr = redisTemplate.opsForValue().get(layoutName1);
        Optional<String> characterVoOpt = Optional.ofNullable(layoutNameStr);

        String settingStr = redisTemplate.opsForValue().get(layoutName2);
        Optional<String> settingVoOpt = Optional.ofNullable(settingStr);
        if (!characterVoOpt.isPresent()) {
            // 如果为空的话在redis中创建默认排版
            SelectedCopyingExamplesValueVo selectedCopyingExamples = (SelectedCopyingExamplesValueVo) layoutEmpty(2, token);
            layoutNameStr = JSON.toJSONString(selectedCopyingExamples.getCharacterList());
            characterVoOpt = Optional.ofNullable(layoutNameStr);

            settingStr = JSON.toJSONString(selectedCopyingExamples.getSetting());
            settingVoOpt = Optional.ofNullable(settingStr);
        }

        List<CharacterVo> character = JsonUtils.toListOfObject(
                characterVoOpt.get(),
                CharacterVo.class,
                JsonUtils.createObjectMapper());
        SelectedCopyingExamplesSettingVo setting = JsonUtils.toObject(
                settingVoOpt.get(),
                SelectedCopyingExamplesSettingVo.class);
        SelectedCopyingExamplesValueVo selectedCopyingExamples = new SelectedCopyingExamplesValueVo(
                character,
                setting
        );
        return ResponseData.success(selectedCopyingExamples);
    }

    /**
     * 保存碑帖临摹到排版
     */
    @ApiOperation("保存碑帖临摹到排版")
    @PostMapping("/layout/steleCalli/save")
    @ApiImplicitParam(name = "Authorization",value = "token",paramType = "header",dataType = "String",required = true)
    public ResponseData layoutSteleCalliSave(@RequestBody CopyingSteleCalligraphyValueVo copyingSteleCalligraphy , @RequestHeader("Authorization") String token) {
        // 判断接收参数空否
        if (copyingSteleCalligraphy == null || copyingSteleCalligraphy.getCharacterList() == null || copyingSteleCalligraphy.getSetting() == null)
            return ResponseData.success("保存失败！",false);
        String layoutName1 = "user:" + token + ":stelecalli:characterlist";
        String layoutName2 = "user:" + token + ":stelecalli:setting";
        redisTemplate.opsForValue().set(layoutName1, JSON.toJSONString(copyingSteleCalligraphy.getCharacterList()), 2, TimeUnit.HOURS);
        redisTemplate.opsForValue().set(layoutName2, JSON.toJSONString(copyingSteleCalligraphy.getSetting()), 2, TimeUnit.HOURS);
        return ResponseData.success("保存成功！");
    }

    /**
     * 获取碑帖临摹排版
     */
    @ApiOperation("获取碑帖临摹排版")
    @PostMapping("/layout/steleCalli/get")
    @ApiImplicitParam(name = "Authorization",value = "token",paramType = "header",dataType = "String",required = true)
    public ResponseData<CopyingSteleCalligraphyValueVo> layoutSteleCalliGet(@RequestHeader("Authorization") String token) {
        String layoutName1 = "user:" + token + ":stelecalli:characterlist";
        String layoutName2 = "user:" + token + ":stelecalli:setting";

        String layoutNameStr = redisTemplate.opsForValue().get(layoutName1);
        Optional<String> characterVoOpt = Optional.ofNullable(layoutNameStr);

        String settingStr = redisTemplate.opsForValue().get(layoutName2);
        Optional<String> settingVoOpt = Optional.ofNullable(settingStr);
        if (!characterVoOpt.isPresent()) {
            // 如果为空的话在redis中创建默认排版
            CopyingSteleCalligraphyValueVo copyingSteleCalligraphy = (CopyingSteleCalligraphyValueVo) layoutEmpty(1, token);
            layoutNameStr = JSON.toJSONString(copyingSteleCalligraphy.getCharacterList());
            characterVoOpt = Optional.ofNullable(layoutNameStr);

            settingStr = JSON.toJSONString(copyingSteleCalligraphy.getSetting());
            settingVoOpt = Optional.ofNullable(settingStr);
        }


        List<CharacterVo> character = JsonUtils.toListOfObject(
                characterVoOpt.get(),
                CharacterVo.class,
                JsonUtils.createObjectMapper());
        CopyingSteleCalligraphySettingVo setting = JsonUtils.toObject(
                settingVoOpt.get(),
                CopyingSteleCalligraphySettingVo.class);
        CopyingSteleCalligraphyValueVo copyingSteleCalligraphy = new CopyingSteleCalligraphyValueVo(
                character,
                setting
        );
        return ResponseData.success(copyingSteleCalligraphy);
    }

    /**
     * 创建空白排版
     * type：1碑帖2精临例字
     */
    private Object layoutEmpty(Integer type, String token) {
        String layoutName1;
        String layoutName2;
        List<FixedInformationDicEntity> fixedInformationDicList = fixedInformationDicService.queryByName(FixedInformationName.CO_CHARACTER_LATTICE);
        if (fixedInformationDicList.size() == 0){
            return null;
        }
        switch (type) {
            case 1:
                // 判断排版是否已经创建
                // 排版内容、选项key
                layoutName1 = "user:" + token + ":stelecalli:characterlist";
                layoutName2 = "user:" + token + ":stelecalli:setting";
                if (redisTemplate.hasKey(layoutName1) || redisTemplate.hasKey(layoutName2)) {
                    // 删除并重新创建
                    redisTemplate.delete(Arrays.asList(layoutName1, layoutName1));
                }
                Integer layoutWidth = 4;
                Integer layoutLength = 7;
                Long chrBgId = fixedInformationDicList.get(0).getId();
                List<CharacterVo> characterList1 = new ArrayList<>();
                for (int i=0; i<layoutWidth*layoutLength; ++i){
                    characterList1.add(new CharacterVo());
                }
                CopyingSteleCalligraphySettingVo setting1 = new CopyingSteleCalligraphySettingVo(layoutWidth, layoutLength, 200, chrBgId);
                redisTemplate.opsForValue().set(layoutName1, JSON.toJSONString(characterList1), 2, TimeUnit.HOURS);
                redisTemplate.opsForValue().set(layoutName2, JSON.toJSONString(setting1), 2, TimeUnit.HOURS);
                CopyingSteleCalligraphyValueVo copyingSteleCalligraphy = new CopyingSteleCalligraphyValueVo(
                        characterList1,
                        setting1
                );
                return copyingSteleCalligraphy;
            case 2:
                layoutName1 = "user:" + token + ":secoexamples:exampleslist";
                layoutName2 = "user:" + token + ":secoexamples:setting";
                if (redisTemplate.hasKey(layoutName1) || redisTemplate.hasKey(layoutName2)) {
                    // 删除并重新创建
                    redisTemplate.delete(Arrays.asList(layoutName1, layoutName1));
                }

                layoutWidth = 4;
                layoutLength = 7;
                chrBgId = fixedInformationDicList.get(0).getId();
                List<CharacterVo> characterList2 = new ArrayList<>();
                for (int i=0; i<layoutWidth*layoutLength; ++i){
                    characterList2.add(new CharacterVo());
                }
                SelectedCopyingExamplesSettingVo setting2 = new SelectedCopyingExamplesSettingVo(layoutWidth, layoutLength, 200, chrBgId);
                redisTemplate.opsForValue().set(layoutName1, JSON.toJSONString(characterList2), 2, TimeUnit.HOURS);
                redisTemplate.opsForValue().set(layoutName2, JSON.toJSONString(setting2), 2, TimeUnit.HOURS);

                SelectedCopyingExamplesValueVo selectedCopyingExamples = new SelectedCopyingExamplesValueVo(
                        characterList2,
                        setting2
                );
                return selectedCopyingExamples;
            case 3:
                break;
        }
        return null;
    }
}
